iT邦幫忙

2022 iThome 鐵人賽

DAY 2
0
Modern Web

後端Developer實戰ClojureScript: Reagent與前端框架 Reframe系列 第 2

[Day02]踏上Clojure / Clojurescript的旅程 - 學習Clojure語法的勇敢與真實

  • 分享至 

  • xImage
  •  

本篇文章以brave clojure的第3章為靈感來介紹clojure基礎語法及特色。

Everything is a list

Ref: Chapter 3: Do Things: A Clojure Crash Course

在clojure(或LISP,LISt Processing,列表處理器)的語法,
有3個主要特色:

  1. everything is a list (verb param1 param2)
  2. everything enclosure returns a value (如果沒有回傳值,通常就回傳nil)
  3. chaining operations:
    • list可以一直不停地往下串(所以結尾就會出現很多括號啦)
    • 運算式的回傳值傳下去可以成為另一個運算式的參數

先以簡單的 1 + 1 = 2 舉例

運算子operator會先擺在第一順位,運算元 operand 放後面。

(operator operand1 operand2 ... operandn)
;; 
(+ 1 1)
;=> 2

(operator operand1 operand2 ... operandn)
第一個位置 + 運算子operator
或者也可以換成任何函式名稱!

然後接著是一或多個參數,(代換掉上面的1 2。)

(str "中秋節" "一家烤肉" "萬家香")
 ; => "中秋節一家烤肉萬家香"

這樣的好處是,LISP程式可以把原始碼當作資料結構進行操作。
你也能用函式定義新的運算子,寫出更複雜的程式。

用來做事的Form

表達資料流程flow control的 if else是每個語言的入門語法,
在clojure裡,
排在第一個的if 就是剛剛everything is a list (verb param1 param2)所說的 verb

(if boolean-form  then-form  optional-else-form)

但基本我們會縮排一下比較好看喇~

(if boolean-form  
  then-form  
  optional-else-form)

來用falsy的nil放在if condition裡舉個例子

(if nil
  "This won't be true because nil is falsey"
  "nil is falsey")
 
 ; => "nil is falsey"
 

讓使簡單的函式聚合起來形成更複雜的函式

以上的例子還是以簡單的字串str舉例,
需要熟悉cheatsheet上的函式
才能做出更複雜的功能唷~

例如:以下的程式代表求取50以內的偶數平方和

(->> (range 50)
     (filter even?)
     (map (fn [x] (* x x)))
     (reduce +))

其中的(fn [x] (* x x)) 就是個匿名函式,可直接傳遞給map函式。

或者,如果想要使用有名字的函式的話,你需要知道def & defn,來定義屬於你自己的函式。

萬丈高樓從地起:先用defn寫一個hello world!

Day2. repo程式碼範例

(ns tutorial.core
  (:gen-class))

(defn -main
  [& args]
  (println "hello world, Tingting!"))

我使用的IDE是 IntelliJ IDEA CE community版本

再安裝Cursive plugin: the full Clojure and ClojureScript language support

按run執行結果會出現 "hello world, Tingting!"

解釋def & defn與的區別

def & defn差在哪呢?
這是新手一開始寫clojure第一個比較容易混淆的誤區

def 本身是一個special form

def這個special form可以視為是function,其用途是用來命名可以操作的變數

def Creates and interns or locates a global var with the name of symbol and a
namespace of the value of the current namespace (ns).
See http://clojure.org/special_forms for more information.

舉個例子?,我定義一個vector harry-potter-series 用來放我買的三本書

;; 如同前面提的,def放在第一個位置,所以它本人是function (operator / verb)

(def harry-potter-series
  ["the Philosopher's Stone" "the Chamber of Secrets" "the Prisoner of Azkaban"])

在command line執行 lein repl

~/Documents/Clojure/tutorial master*
❯ lein repl
nREPL server started on port 56722 on host 127.0.0.1 - nrepl://127.0.0.1:56722
REPL-y 0.4.4, nREPL 0.8.3
Clojure 1.10.1
OpenJDK 64-Bit Server VM 1.8.0_312-b07
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

啟動REPL成功後,
輸入harry-potter-series,三本書就列出來啦~

tutorial.core=> harry-potter-series
["the Philosopher's Stone" "the Chamber of Secrets" "the Prisoner of Azkaban"]

defn 是一個structure form,用來定義函式

稍微改寫一下剛剛的hello world,讓它能傳參數進去

(defn -main
  [number]
  (println "hello world, Tingting!")
  (println "I bought"  number  "harry potter series"))

呼叫main函式 (-main 3)

tutorial.core=> (-main 3)
hello world, Tingting!
I bought 3 harry potter series
nil 
;;everything enclosure returns a value。println沒有回傳值,所以回傳nil

defn 與 def 轉換

defn 文件裡有說明跟def是可以轉換的

Same as 
(def name (fn [params* ] exprs*)) 
(def name (fn ([params* ] exprs*)+)) 

舉個例子,(defn x [a b] (+ a b))
等於def裡面放匿名函式 (def y (fn [a b] (+ a b)))

tutorial.core=> (defn x [a b] (+ a b))
#'tutorial.core/x
tutorial.core=> (def y (fn [a b] (+ a b)))
#'tutorial.core/y
tutorial.core=> (x 2 3)
5
tutorial.core=> (y 2 3)
5

很神奇吧!
多看幾次defn熟練之後就可以無痛轉換def了~

明天要來介紹javascript與clojurescript的語法差別:)


上一篇
[Day01] 探索Clojure / Clojurescript 之開賽宣言
下一篇
[Day03] Javascript vs Clojurescript - def & defn 比較
系列文
後端Developer實戰ClojureScript: Reagent與前端框架 Reframe30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Bater
iT邦新手 4 級 ‧ 2022-09-20 08:50:19

1+1=2為例,範例程式卻是1+2喲

感謝細心校稿~已更正 <3

我要留言

立即登入留言